import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.*;
//import org.apache.commons.io.FileUtils;
import com.spire.presentation.*;
import com.spire.presentation.drawing.FillFormatType;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
//import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.regex.Pattern;

/**
 * Word、Excel、Pdf、Ppt添加水印
 *
 * @date   2021-11-01
 * @author     Twinkle
 */
public class OfficeWaterMarkUtil {

    public static byte[] getBytesByFile(String pathStr) {
        File file = new File(pathStr);
        try {
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            byte[] data = bos.toByteArray();
            bos.close();
            return data;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void addWaterMarkOffice(String inputSrc, String outputSrc, String waterMark){
        File file = new File(inputSrc);
        String fileName = file.getName();

        if (fileName.toLowerCase().endsWith("pdf")) {
            addPDFWaterMark(inputSrc, outputSrc, waterMark);
        } else if (fileName.toLowerCase().endsWith("xlsx") || fileName.toLowerCase().endsWith("xls")) {
            addExcelWaterMark(inputSrc, outputSrc, waterMark);
        } else if (fileName.toLowerCase().endsWith("docx") || fileName.toLowerCase().endsWith("doc")) {
            addWordWaterMark(inputSrc, outputSrc, waterMark);
        }else if (fileName.toLowerCase().endsWith("pptx") || fileName.toLowerCase().endsWith("ppt")) {
            addPptWaterMark(inputSrc, outputSrc, waterMark);
        }
    }

    /**
     * pdf文件添加文字水印
     *
     * @param fileData      原始文件字节数组
     * @param outSrc        文件输出路径
     * @param waterMarkName 水印内容
     */
//    private static void addPDFWaterMark(byte[] fileData, String outSrc, String waterMarkName) throws Exception {
//
//        PdfReader reader = null;
//        PdfStamper stamper = null;
//        try {
//            reader = new PdfReader(fileData);
//            stamper = new PdfStamper(reader, new FileOutputStream(outSrc));
//
//            BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", com.itextpdf.text.pdf.BaseFont.EMBEDDED);
//            PdfGState gs = new PdfGState();
//            gs.setFillOpacity(0.3f);
//            gs.setStrokeOpacity(0.4f);
//            PdfContentByte under = null;
//            Rectangle pageRect = null;
//            for (int i = 1, n = reader.getNumberOfPages(); i <= n; i++) {
//                pageRect = reader.getPageSizeWithRotation(i);
//                // 计算水印X,Y坐标
//                float x = pageRect.getWidth() / 2;
//                float y = pageRect.getHeight() / 2;
//                under = stamper.getOverContent(i);
//                under.saveState();
//                under.setGState(gs);
//                under.beginText();
//                under.setFontAndSize(base, 20);
//                under.showTextAligned(Element.ALIGN_CENTER, waterMarkName, x, y, 30);
//                under.endText();
//            }
//        } finally { // 关闭流
//            if (stamper != null) {
//                stamper.close();
//            }
//            if (reader != null) {
//                reader.close();
//            }
//        }
//    }

    /**
     * word文件添加文字水印
     *
     * @param fileData      原始文件字节数组
     * @param outputSrc     文件输出路径
     * @param waterMarkName 水印内容
     */
//    private static void addWordWaterMark(byte[] fileData, String outputSrc, String waterMarkName) throws Exception {
//
//        InputStream input = new ByteArrayInputStream(fileData);
//        XWPFDocument doc = new XWPFDocument(input);
//        XWPFHeaderFooterPolicy headerFooterPolicy = doc.createHeaderFooterPolicy();
//        //添加文字水印
//        headerFooterPolicy.createWatermark(waterMarkName);
//        XWPFHeader header = headerFooterPolicy.getHeader(XWPFHeaderFooterPolicy.DEFAULT);
//        XWPFParagraph paragraph = header.getParagraphArray(0);
//        paragraph.getCTP().newCursor();
//        XmlObject[] xmlobjects = paragraph.getCTP().getRArray(0).getPictArray(0).selectChildren(new QName("urn:schemas-microsoft-com:vml", "shape"));
//        if (xmlobjects.length > 0) {
//            CTShape ctshape = (CTShape) xmlobjects[0];
//            //设置水印颜色
//            ctshape.setFillcolor("#828282");
//            //修改水印样式
//            ctshape.setStyle(getWaterMarkStyle(ctshape.getStyle(), 23) + ";rotation:315");
//        }
//        ByteArrayOutputStream out = new ByteArrayOutputStream();
//        try {
//            doc.write(out);
//        } finally {
//            out.close();
//        }
//        out.writeTo(new BufferedOutputStream(new FileOutputStream(outputSrc)));
//    }

    /**
     *pdf文件添加文字水印
     *
     * @param input         原PDF位置
     * @param output        输出文件的位置
     * @param waterMarkName 页脚添加水印
     */
    public static void addPDFWaterMark(String input, String output, String waterMarkName) {
        BufferedOutputStream bos = null;
        try {
            bos = new BufferedOutputStream(new FileOutputStream(new File(output)));
            com.itextpdf.text.pdf.PdfReader reader = new com.itextpdf.text.pdf.PdfReader(input);
            com.itextpdf.text.pdf.PdfStamper stamper = new com.itextpdf.text.pdf.PdfStamper(reader, bos);

            // 获取总页数 +1, 下面从1开始遍历
            int total = reader.getNumberOfPages() + 1;
            // 使用classpath下面的字体库
            com.itextpdf.text.pdf.BaseFont base = null;
            try {
                base = com.itextpdf.text.pdf.BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", com.itextpdf.text.pdf.BaseFont.EMBEDDED);
            } catch (Exception e) {
                // 日志处理
                e.printStackTrace();
            }

            // 间隔
            int interval = -15;
            // 获取水印文字的高度和宽度
            int textH = 0, textW = 0;
            JLabel label = new JLabel();
            label.setText(waterMarkName);
            FontMetrics metrics = label.getFontMetrics(label.getFont());
            textH = metrics.getHeight();
            textW = metrics.stringWidth(label.getText());
            System.out.println("textH: " + textH);
            System.out.println("textW: " + textW);

            // 设置水印透明度
            com.itextpdf.text.pdf.PdfGState gs = new com.itextpdf.text.pdf.PdfGState();
            gs.setFillOpacity(0.2f);
            gs.setStrokeOpacity(0.7f);

            com.itextpdf.text.Rectangle pageSizeWithRotation = null;
            PdfContentByte content = null;
            for (int i = 1; i < total; i++) {
                // 在内容上方加水印
                content = stamper.getOverContent(i);
                // 在内容下方加水印
                // content = stamper.getUnderContent(i);
                content.saveState();
                content.setGState(gs);

                // 设置字体和字体大小
                content.beginText();
                content.setFontAndSize(base, 20);

                // 获取每一页的高度、宽度
                pageSizeWithRotation = reader.getPageSizeWithRotation(i);
                float pageHeight = pageSizeWithRotation.getHeight();
                float pageWidth = pageSizeWithRotation.getWidth();

                // 根据纸张大小多次添加， 水印文字成30度角倾斜
                for (int height = interval + textH; height < pageHeight; height = height + textH * 6) {
                    for (int width = interval + textW; width < pageWidth + textW; width = width + textW * 2) {
                        content.showTextAligned(Element.ALIGN_LEFT, waterMarkName, width - textW, height - textH, 30);
                    }
                }

                content.endText();
            }

            // 关流
            stamper.close();
            reader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    /**
     * 设置水印格式
     * word
     *
     * @param styleStr
     * @param height
     * @return
     */
    public static String getWaterMarkStyle(String styleStr, double height) {
        Pattern p = Pattern.compile(";");
        String[] strs = p.split(styleStr);
        for (String str : strs) {
            if (str.startsWith("height:")) {
                String heightStr = "height:" + height + "pt";
                styleStr = styleStr.replace(str, heightStr);
                break;
            }
        }
        return styleStr;
    }

    /**
     * excel添加水印
     *
     * @param inputSrc      原始文件路径
     * @param outputSrc     生成文件路径
     * @param waterMarkName 水印内容
     */
    private static void addExcelWaterMark(String inputSrc, String outputSrc, String waterMarkName) {
        byte[] fileData = OfficeWaterMarkUtil.getBytesByFile(inputSrc);
        BufferedImage image = createWaterMarkImage(waterMarkName);
        // 导出到字节流B
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "png", os);
            InputStream sbs = new ByteArrayInputStream(fileData);
            XSSFWorkbook workbook = new XSSFWorkbook(sbs);
            int pictureIdx = workbook.addPicture(os.toByteArray(), Workbook.PICTURE_TYPE_PNG);
            POIXMLDocumentPart poixmlDocumentPart = workbook.getAllPictures().get(pictureIdx);

            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {//获取每个Sheet表
                XSSFSheet sheet = workbook.getSheetAt(i);
                PackagePartName ppn = poixmlDocumentPart.getPackagePart().getPartName();
                String relType = XSSFRelation.IMAGES.getRelation();
                PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
                sheet.getCTWorksheet().addNewPicture().setId(pr.getId());
            }
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            try {
                workbook.write(bos);
            } finally {
                bos.close();
            }
            bos.writeTo(new BufferedOutputStream(new FileOutputStream(outputSrc)));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    /**
     * 创建水印图片
     * excel
     *
     * @param waterMark 水印内容
     * @return
     */

    public static BufferedImage createWaterMarkImage(String waterMark) {
        String[] textArray = waterMark.split("\n");
        Font font = new Font("microsoft-yahei", Font.PLAIN, 20);
        Integer width = 500;
        Integer height = 200;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        // 背景透明 开始
        Graphics2D g = image.createGraphics();
        image = g.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        g.dispose();
        // 背景透明 结束
        g = image.createGraphics();
        g.setColor(new Color(Integer.parseInt("#C5CBCF".substring(1), 16)));// 设定画笔颜色
        g.setFont(font);// 设置画笔字体
        g.shear(0.1, -0.26);// 设定倾斜度
        // 设置字体平滑
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        int y = 150;
        for (int i = 0; i < textArray.length; i++) {
            g.drawString(textArray[i], 0, y);// 画出字符串
            y = y + font.getSize();
        }
        g.dispose();// 释放画笔
        return image;
    }

    /**
     * word文字水印
     *
     * @param inputPath
     * @param outPath
     * @param markStr
     */
    public static void addWordWaterMark(String inputPath, String outPath, String markStr) {
        File inputFile = new File(inputPath);
        //2003doc 用HWPFDocument  ； 2007doc 用 XWPFDocument
        XWPFDocument doc = null;
        try {
            // 延迟解析比率
            //ZipSecureFile.setMinInflateRatio(-1.0d);
            doc = new XWPFDocument(new FileInputStream(inputFile));
        } catch (FileNotFoundException e) {
            //throw new MyException(ResultCode.FAILURE, "源文件不存在");
        } catch (IOException e) {
            //throw new MyException(ResultCode.FAILURE, "读取源文件IO异常");
        } catch (Exception e) {
            //throw new MyException(ResultCode.FAILURE, "不支持的文档格式");
        }
        XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy();

        //添加水印
        headerFooterPolicy.createWatermark(markStr);
        File file = new File(outPath);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                //throw new MyException(ResultCode.FAILURE, "创建输出文件失败");
            }
        }
        OutputStream os = null;
        try {
            os = new FileOutputStream(outPath);
            doc.write(os);
        } catch (FileNotFoundException e) {
            //throw new MyException(ResultCode.FAILURE, "创建输出文件失败");
        } catch (Exception e) {
            //throw new MyException(ResultCode.FAILURE, "添加文档水印失败");
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    /**
     * ppt文字水印
     *
     * @param inputPath
     * @param outPath
     * @param markStr
     */
    public static void addPptWaterMark(String inputPath, String outPath, String markStr) {
        //加载PPT源文档
        Presentation ppt = new Presentation();
        try {
            ppt.loadFromFile(inputPath);
            ISlide slide = null;
            //获取指定幻灯片
            for (int o = 0; o < ppt.getSlides().getCount(); o++) {
                slide = ppt.getSlides().get(o);

                //设置文本水印文本宽和高
                int width= 110;
                int height= 80;

                //起始坐标
                float x = 10;
                float y = 40;
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        //绘制文本，设置文本格式并将其添加到第一张幻灯片
                        Rectangle2D.Double rect = new Rectangle2D.Double(x,y,width, height);
                        IAutoShape shape = slide.getShapes().appendShape(ShapeType.RECTANGLE, rect);
                        shape.getFill().setFillType(FillFormatType.NONE);
                        shape.getShapeStyle().getLineColor().setColor(Color.white);
                        shape.setRotation(-45);
                        shape.getLocking().setSelectionProtection(true);
                        shape.getLine().setFillType(FillFormatType.NONE);
                        shape.getTextFrame().setText(markStr);
                        shape.setShapeArrange(ShapeAlignmentEnum.ShapeArrange.SendToBack);
                        PortionEx textRange = shape.getTextFrame().getTextRange();
                        textRange.getFill().setFillType(FillFormatType.SOLID);
                        textRange.getFill().getSolidColor().setColor(new Color(Integer.parseInt("#C5CBCF".substring(1), 16)));
                        textRange.setFontHeight(20);
                        x += (100 + ppt.getSlideSize().getSize().getWidth()/6);
                    }
                    x = 30;
                    y += (100 + ppt.getSlideSize().getSize().getHeight()/7) ;
                }
            }

            //保存文档
            ppt.saveToFile(outPath, FileFormat.PPTX_2013);
            ppt.dispose();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}